package com.wenx.v3auth.service;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.wenx.v3core.response.R;
import com.wenx.v3openfeign.api.SysUserRemoteInfra;
import com.wenx.v3openfeign.dto.UserAuthInfoDto;
import com.wenx.v3secure.user.UserDetail;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CachePut;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.Set;

/**
 * V3自定义用户详情服务
 * 基于Enhanced RBAC权限模型
 * 支持多种查询方式和容错处理机制
 * 
 * @author wenx
 * @version 2.0.0
 */
@Slf4j
@Service("v3CustomUserDetailsService")
@RequiredArgsConstructor
public class V3CustomUserDetailsService implements UserDetailsService {

    // 缓存常量
    private static final String USER_DETAILS_CACHE = "auth:user:details";
    
    private final SysUserRemoteInfra sysUserRemoteInfra;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (StrUtil.isBlank(username)) {
            log.warn("用户名为空，拒绝认证");
            throw new UsernameNotFoundException("用户名不能为空");
        }
        
        log.debug("开始加载用户认证信息: {}", username);
        try {
            return getUserAuthInfoWithFallback(username)
                .map(this::buildUserDetailWithCache)
                .orElseThrow(() -> {
                    log.warn("用户不存在或认证信息获取失败: {}", username);
                    return new UsernameNotFoundException("用户不存在: " + username);
                });
        } catch (UsernameNotFoundException e) {
            throw e;
        } catch (Exception e) {
            log.error("加载用户认证信息时发生异常: username={}", username, e);
            throw new UsernameNotFoundException("认证服务异常: " + e.getMessage(), e);
        }
    }
    
    /**
     * 从缓存获取用户详情
     */
    @Cacheable(value = USER_DETAILS_CACHE, key = "'user:' + #username")
    public UserDetail getCachedUserDetail(String username) {
        // 如果缓存中没有数据，会返回null
        return null;
    }

    /**
     * 获取用户认证信息
     * 直接使用通用标识符查询接口
     */
    private Optional<UserAuthInfoDto> getUserAuthInfoWithFallback(String identifier) {
        if (StrUtil.isBlank(identifier)) {
            return Optional.empty();
        }
        
        // 处理带sys:前缀的用户名
        String actualIdentifier = identifier;
        if (identifier.startsWith("sys:")) {
            actualIdentifier = identifier.substring(4); // 去除"sys:"前缀
            log.debug("检测到sys:前缀，处理后的标识符: {}", actualIdentifier);
        }
        
        try {
            log.debug("获取用户认证信息: {}", actualIdentifier);
            R result = sysUserRemoteInfra.getUserAuthInfo(actualIdentifier);
            
            if (isSuccessResult(result)) {
                UserAuthInfoDto userAuthInfo = parseUserAuthInfo(result);
                if (userAuthInfo != null) {
                    log.info("用户认证信息获取成功: 用户ID={}, 用户名={}", 
                        userAuthInfo.getId(), userAuthInfo.getUsername());
                    return Optional.of(userAuthInfo);
                }
            }
            
            log.warn("用户认证信息获取失败: {}", identifier);
            return Optional.empty();
            
        } catch (Exception e) {
            log.error("获取用户认证信息异常: identifier={}", identifier, e);
            return Optional.empty();
        }
    }
    
    /**
     * 解析用户认证信息
     */
    private UserAuthInfoDto parseUserAuthInfo(R result) {
        try {
            return JSON.parseObject(
                JSON.toJSONString(result.getData()), 
                UserAuthInfoDto.class
            );
        } catch (Exception e) {
            log.error("解析用户认证信息失败", e);
            return null;
        }
    }

    /**
     * 构建用户详情对象并缓存
     * 只有成功构建用户详情时才进行缓存
     */
    @CachePut(value = USER_DETAILS_CACHE, key = "'user:' + #userAuthInfo.username")
    public UserDetail buildUserDetailWithCache(UserAuthInfoDto userAuthInfo) {
        return buildUserDetail(userAuthInfo);
    }
    
    /**
     * 构建用户详情对象
     * 基于Enhanced RBAC权限模型
     */
    private UserDetail buildUserDetail(UserAuthInfoDto userAuthInfo) {
        try {
            UserDetail userDetail = new UserDetail();
            
            // 复制基本属性
            BeanUtils.copyProperties(userAuthInfo, userDetail);
            
            // 设置权限集合（容错处理）
            Set<String> permissions = Optional.ofNullable(userAuthInfo.getPermissions())
                .filter(perms -> !perms.isEmpty())
                .orElse(Set.of("ROLE_USER"));
            
            userDetail.setAuthoritySet(permissions);
            
            // 验证用户状态
            validateUserStatus(userAuthInfo);
            
            log.info("用户详情构建成功: 用户ID={}, 用户名={}, 权限数量={}, 角色数量={}", 
                userAuthInfo.getId(), 
                userAuthInfo.getUsername(), 
                permissions.size(),
                Optional.ofNullable(userAuthInfo.getRoleIds()).map(Set::size).orElse(0));
            
            return userDetail;
            
        } catch (Exception e) {
            log.error("构建用户详情失败: 用户ID={}, 用户名={}", 
                userAuthInfo.getId(), userAuthInfo.getUsername(), e);
            throw new UsernameNotFoundException("用户详情构建失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 验证用户状态
     */
    private void validateUserStatus(UserAuthInfoDto userAuthInfo) {
        if (userAuthInfo.getStatus() == null || userAuthInfo.getStatus() != 1) {
            log.warn("用户状态异常: 用户ID={}, 状态={}", userAuthInfo.getId(), userAuthInfo.getStatus());
            throw new UsernameNotFoundException("用户账户已被禁用或状态异常");
        }
    }
    
    /**
     * 判断结果是否成功
     */
    private boolean isSuccessResult(R result) {
        return result != null && ObjectUtil.equal(result.getCode(), 0L) && result.getData() != null;
    }
    

}